package com.evil.application.strategy.reporting;

import cn.hutool.core.collection.CollectionUtil;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import com.evil.application.enums.reporting.ReportingTypeEnum;
import com.evil.application.pojo.dto.reporting.AggBaseDTO;
import com.evil.application.pojo.dto.reporting.ApplicationReportingDTO;
import com.evil.application.pojo.dto.reporting.data.ReportingDataRespDTO;
import com.evil.common.core.util.StreamUtil;
import com.evil.common.es.dto.AggTreeParam;
import com.evil.common.es.dto.AggTreeResult;
import lombok.Data;

import java.util.*;

/**
 * 报表类型-接口
 *
 * @author liyang
 * @date 2022-08-08 00:00
 */
public interface ReportingData {

    ReportingTypeEnum type();

    /**
     * 统计
     *
     * @param reportingDTO reportingDTO
     * @param aggregations aggregations
     * @return ReportingDataRespDTO
     */
    ReportingDataRespDTO calculation(ApplicationReportingDTO reportingDTO, Aggregate aggregations);

    default AggTreeParam<AggBaseDTO> analysisAggTreeParam(ApplicationReportingDTO reportingDTO) {
        // 行维度名称列表，示例数据：["A", "C-行"]
        LinkedHashMap<String, ? extends AggBaseDTO> rowNames = StreamUtil.toOrderlyMapK(reportingDTO.getReportingHeaders(), AggBaseDTO::getTitle);
        // 列维度名称列表，示例数据：["C-列", "创建时间"]
        LinkedHashMap<String, ? extends AggBaseDTO> columnNames = StreamUtil.toOrderlyMapK(reportingDTO.getReportingColumnHeaders(), AggBaseDTO::getTitle);
        // 指标名称列表，示例数据：["数字"]
        LinkedHashMap<String, ? extends AggBaseDTO> targetNames = StreamUtil.toOrderlyMapK(reportingDTO.getReportingTargets(), AggBaseDTO::getTitle);
        // 聚合树信息
        return new AggTreeParam<>(rowNames, columnNames, targetNames);
    }

    default void analysisAggTree(List<AggTreeResult> aggTree, Analysis analysis) {
        if (CollectionUtil.isEmpty(aggTree)) {
            return;
        }
        for (int i = 0, l = aggTree.size() - 1; i <= l; i++) {
            AggTreeResult a = aggTree.get(i);
            switch (a.getDimensionEnum()) {
                case ROW -> {
                    analysis.getRowKeyMap().append(a.getTitle(), a.getValue());
                    if (i > 0 || a.getChildren().size() == 0) {
                        analysis.rowNumIncrement();
                    }
                }
                case COLUMN -> analysis.getCellKeyMap().append(a.getTitle(), a.getValue());
            }
            this.analysisAggTree(a.getChildren(), analysis);
        }
    }

    @Data
    class Analysis {
        private final AggTreeParam<AggBaseDTO> param;
        private final AggKey rowKeyMap;
        private final AggKey cellKeyMap;

        private int rowNum = 0;

        public Analysis(AggTreeParam<AggBaseDTO> param) {
            this.param = param;
            this.rowKeyMap = new AggKey();
            this.cellKeyMap = new AggKey();
        }

        public void rowNumIncrement() {
            this.rowNum++;
        }
    }

    class AggKey extends LinkedHashMap<String, LinkedHashSet<String>> {
        private final ArrayList<String> keys;

        public AggKey() {
            super();
            this.keys = new ArrayList<>();
        }

        public void append(String key, Object value) {
            if (!this.containsKey(key)) {
                keys.add(key);
                this.put(key, new LinkedHashSet<>());
            }
            this.get(key).add(null == value ? "" : value.toString());
        }

        public Optional<String> getKey(int index) {
            if (keys.size() <= index) {
                return Optional.empty();
            }
            return Optional.ofNullable(keys.get(index));
        }

        public Optional<String> getNextKey(String key) {
            int index = keys.indexOf(key);
            return this.getKey(index + 1);
        }

        public Optional<LinkedHashSet<String>> getNextValue(String key) {
            int index = keys.indexOf(key);
            return this.getKey(index + 1).map(this::get);
        }
    }
}
